package com.mvc.rpc;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.mvc.common.Res;
import com.mvc.common.tools.HttpUtil;
import com.mvc.rpc.feign.RemoteProcedureCallFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * RPC代理
 * @author JayEinstein
 */
@Slf4j
public class RpcServiceProxy implements MethodInterceptor {

    private Class<?> objectType;

    private String host;

    private RemoteProcedureCallFeign remoteProcedureCallFeign;

    public RpcServiceProxy(Class<?> objectType) {
        this.objectType = objectType;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public RemoteProcedureCallFeign getRemoteProcedureCallFeign() {
        return remoteProcedureCallFeign;
    }

    public void setRemoteProcedureCallFeign(RemoteProcedureCallFeign remoteProcedureCallFeign) {
        this.remoteProcedureCallFeign = remoteProcedureCallFeign;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        if (Object.class.equals(method.getDeclaringClass())) {
            return method.invoke(this, objects);
        }

        CallMethod callMethod = new CallMethod();

        callMethod.setBeanClass(objectType.getName());
        callMethod.setMethodName(method.getName());
        // 封装请求参数
        if (objects != null) {
            List<ArgHolder> argHolders = new ArrayList<>(method.getParameterCount());
            Class<?>[] parameterTypes = method.getParameterTypes();
            for (int i = 0; i < parameterTypes.length; i++) {
                Class<?> parameterType = parameterTypes[i];
                Object val = objects[i];
                ArgHolder arg = new ArgHolder(parameterType, val);
                argHolders.add(arg);
            }
            callMethod.setArgHolders(argHolders);
        }

        // 远程调用
        Res<String> call = remoteProcedureCallFeign.call(callMethod);

        // 获得返回结果
        String data = Res.getData(call);

        // 返回类型封装
        Class<?> returnType = method.getReturnType();

        if (void.class == returnType) {
            return null;
        }

        Type genericReturnType = method.getGenericReturnType();

        try {
            return JSON.parseObject(data, genericReturnType);
        } catch (Exception e) {
            log.error("看到这个错误，是框架出了问题，请手动完善框架");
            log.error("{} 转成 {} 出现错误", data, genericReturnType);
            throw new RuntimeException(e);
        }

    }

}
